/*
 * @Author: soso
 * @Date: 2022-02-22 17:30:24
 * @LastEditTime: 2022-03-11 17:34:01
 * @LastEditors: Please set LastEditors
 * @Description: 归档命令
 * @FilePath: /gomeshsync/cfile/arch.go
 */

package cfile

import (
	"log"

	"gitee.com/kimsoso/go-utils/revfile"
	"github.com/vmihailenco/msgpack"
)

type arch struct {
	rfile revfile.Revfile //磁盘文件

	caKeysMap map[int]int // 缓存map
	caCmds    []*MCommand //缓存cmd
	lk        int32       // lastkey
}

func NewArch(path string) *arch {
	arch := &arch{
		rfile:     revfile.NewRevFile(path),
		caKeysMap: map[int]int{},
		caCmds:    []*MCommand{},
	}
	return arch
}

// 清除缓存
func (ar *arch) clearCache() {
	ar.caKeysMap = map[int]int{}
	ar.caCmds = []*MCommand{}
	ar.lk = -1
}

// 从keyfrom开始读取命令序列
func (ar *arch) getCommandsFrom(keyfrom int) (out []*MCommand) {
	if len(ar.caCmds) > 0 && ar.caCmds[0].Ck == keyfrom {
		return ar.caCmds
	}

	out = []*MCommand{}
	if ar.lastKey() < int32(keyfrom) {
		return
	}

	ar.rfile.Read(func(data []byte) bool {
		cmds := []*MCommand{}

		if err := msgpack.Unmarshal(data, &cmds); err != nil {
			log.Println("Arch Unmarshal error:", err)
			return false

		} else {
			clen := len(cmds)
			for i := clen - 1; i >= 0; i-- {
				cmd := cmds[i]
				if cmd.Ck >= keyfrom {
					out = append([]*MCommand{cmd}, out...)
				} else {
					return false
				}
			}
			return true
		}
	})

	if len(out) > 0 {
		ar.caKeysMap = map[int]int{}
		ar.caCmds = out
		for i, cmd := range ar.caCmds {
			ar.caKeysMap[cmd.Ck] = i
		}
	}
	return
}

// 归档文件的下一个Key
func (ar *arch) lastKey() int32 {
	if ar.lk >= 0 {
		return ar.lk
	}

	if len(ar.caCmds) > 0 {
		ar.lk = int32(ar.caCmds[len(ar.caCmds)-1].Ck)
	} else {
		cmds := []*MCommand{}
		ar.rfile.Read(func(data []byte) bool {
			msgpack.Unmarshal(data, &cmds)
			return false
		})

		if len(cmds) > 0 {
			ar.lk = int32(cmds[len(cmds)-1].Ck)
		} else {
			ar.lk = -1
		}
	}
	return ar.lk
}
